﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;

namespace Dtf.Core.Utilities
{
    /// <summary>
    /// From Mita
    /// </summary>
    public class Highlighter : System.Windows.Forms.Form
    {
        // Fields
        private bool _disposed;
        private Rectangle _innerRectangle;
        private Rectangle _outerRectangle;
        private HighlighterProperties _properties;

        // Methods
        public Highlighter()
            : this(HighlighterProperties.Default)
        {
        }

        public Highlighter(HighlighterProperties properties)
        {
            base.TopMost = true;
            if (properties==null)
            {
                throw new ArgumentNullException("properties is null"); 
            }

            this._disposed = false;
            this._properties = properties;
            this.BackColor = this._properties.Color;
            this.ForeColor = Color.Black;
            base.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            base.MaximizeBox = false;
            base.MinimizeBox = false;
            base.Name = "HighlighterWindow";
            base.ShowInTaskbar = false;
            base.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
            this.Text = base.Name;
            base.TopMost = true;
        }

        protected override void Dispose(bool disposing)
        {
            if (!this._disposed)
            {
                base.Dispose(disposing);
                this._disposed = true;
            }
        }

        internal static void Highlight(UIItem item)
        {
            Highlight(item.BoundingRectangle, HighlighterProperties.Default);
        }

        internal static void Highlight(UIItem item, HighlighterProperties properties)
        {
            Highlight(item.BoundingRectangle, properties);
        }

        internal static void Highlight(Rectangle rectangle, HighlighterProperties properties)
        {
            SynchronizationContext syncContext = AsyncOperationManager.SynchronizationContext;
            Thread highlighterThread = new Thread(delegate()
            {
                Highlighter highlighter = new Highlighter(properties);
                System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(){
                    Interval = (int)highlighter.Properties.Timeout.TotalMilliseconds
                };
                timer.Tick += delegate(object sender, EventArgs e)
                {
                    System.Windows.Forms.Application.ExitThread();
                };
                timer.Enabled = true;
                highlighter.SetLocation(rectangle);
                System.Windows.Forms.Application.Run(highlighter);
            });
            highlighterThread.Start();
            highlighterThread.Join();
            AsyncOperationManager.SynchronizationContext = syncContext;
        }

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            Rectangle tmpOuterRectangle = new Rectangle(this._outerRectangle.Left, this._outerRectangle.Top, this._outerRectangle.Width - 1, this._outerRectangle.Height - 1);
            Rectangle tmpInnerRectangle = new Rectangle(this._innerRectangle.Left - 1, this._innerRectangle.Top - 1, this._innerRectangle.Width + 1, this._innerRectangle.Height + 1);
            e.Graphics.DrawRectangle(new Pen(this.ForeColor), tmpInnerRectangle);
            e.Graphics.DrawRectangle(new Pen(this.ForeColor), tmpOuterRectangle);
        }

        public void SetLocation(Rectangle rectangle)
        {
            int totalBorder = this._properties.BorderBuffer + this._properties.BorderWidth;
            this._outerRectangle = new Rectangle(new Point(0, 0), rectangle.Size + new Size(totalBorder * 2, totalBorder * 2));
            this._innerRectangle = new Rectangle(new Point(this._properties.BorderWidth, this._properties.BorderWidth), rectangle.Size + new Size(this._properties.BorderBuffer * 2, this._properties.BorderBuffer * 2));
            Region frmRegion = new Region(this._outerRectangle);
            frmRegion.Exclude(this._innerRectangle);
            base.Location = rectangle.Location - new Size(totalBorder, totalBorder);
            base.Size = this._outerRectangle.Size;
            base.Region = frmRegion;
        }

        public new void Show()
        {
            NativeMethods.SetWindowPos(base.Handle, IntPtr.Zero, 0, 0, 0, 0, 0x53);
        }

        // Properties
        protected HighlighterProperties Properties
        {
            get
            {
                return this._properties;
            }
        }

        // Nested Types
        private static class NativeMethods
        {
            // Fields
            public const int SWP_NOACTIVATE = 0x10;
            public const int SWP_NOMOVE = 2;
            public const int SWP_NOSIZE = 1;
            public const int SWP_SHOWWINDOW = 0x40;

            // Methods
            [DllImport("user32.dll")]
            public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cX, int cY, uint uFlags);
        }
    }


    /// <summary>
    /// From Mita
    /// </summary>
    public class HighlighterProperties
    {
        // Fields
        private int _borderBuffer = 1;
        private int _borderWidth = 5;
        private Color _color = Color.Yellow;
        private static HighlighterProperties _defaultProperties = new HighlighterProperties();
        private TimeSpan _timeout = TimeSpan.FromSeconds(5.0);

        // Properties
        public int BorderBuffer
        {
            get
            {
                return this._borderBuffer;
            }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("ParameterMustBeGreaterThanZero", "BorderBuffer");
                }
                this._borderBuffer = value;
            }
        }

        public int BorderWidth
        {
            get
            {
                return this._borderWidth;
            }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("BorderWidthMustBeGreaterThanZero", "BorderWidth");
                }
                this._borderWidth = value;
            }
        }

        public Color Color
        {
            get
            {
                return this._color;
            }
            set
            {
                this._color = value;
            }
        }

        public static HighlighterProperties Default
        {
            get
            {
                return _defaultProperties;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value is null");
                }
                _defaultProperties = value;
            }
        }

        public TimeSpan Timeout
        {
            get
            {
                return this._timeout;
            }
            set
            {
                this._timeout = value;
            }
        }
    }



}
